﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace WpfApp1
{
    /// <summary>
    /// Window2.xaml 的交互逻辑
    /// 
    /// 
    /// Windows Presentation Foundation(WPF)为您提供了设计自己的对话框的方法。对话框是带有特定意图和用户体验的窗口。
    /// 本文讨论了对话框的工作方式，以及可以创建和使用哪些类型的对话框。对话框用于:
    /// 1. 显示特定的信息给用户。
    /// 2. 从用户处收集信息。
    /// 3. 两者都显示和收集信息。
    /// 4. 显示操作系统提示符，如打印窗口。
    /// 5. 选择一个文件或文件夹。
    /// 这些类型的窗口称为对话框。对话框可以以两种方式显示:模态和非模态。
    /// 
    /// **模态对话框**
    /// 向用户显示模态对话框是应用程序中断正在做的事情，直到用户关闭对话框的一种技术。这通常以提示或警告的形式
    /// 出现。在对话框关闭之前，应用程序中的其他窗口不能与之交互。关闭模态对话框后，应用程序继续运行。最常见的
    /// 对话框用于显示打开的文件或保存文件提示、显示打印机对话框或向用户发送带有某些状态的消息。
    /// 
    /// **非模态对话框**
    /// 不会阻止用户在它打开时激活其他窗口。例如，如果用户希望查找文档中某个特定单词的出现情况，那么主窗口通常
    /// 会打开一个对话框，询问用户正在查找哪个单词。由于应用程序不想阻止用户编辑文档，因此对话框不需要是模态的。
    /// 非模态对话框至少提供一个关闭按钮来关闭对话框。还可以提供其他按钮来运行特定的功能，例如在单词搜索中查找
    /// 下一个单词的Find Next按钮。
    /// 
    /// 使用WPF，您可以创建几种类型的对话框，例如消息框、通用对话框 和 自定义对话框。
    /// 本文讨论了每种方法，对话框示例提供了匹配的示例。
    /// </summary>
    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Get the main window
        /// 
        /// 您可以通过检查Application来访问选择为主窗口的窗口。主窗口属性。
        /// 当单击按钮时，下面的代码将显示一个带有主窗口标题的消息框:
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _Button_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show($"The main window's title is: {Application.Current.MainWindow.Title}");

            // Create a window and make the current window its owner
            var ownedWindow = new Window2Child();
            ownedWindow.Owner = this;
            ownedWindow.Show();
        }

        /// <summary>
        /// 使用Show方法打开的窗口与创建它的窗口没有隐式关系。用户可以独立地与任意一个窗口进行交互，这意味着任意一个窗口
        /// 都可以执行以下操作:
        /// 1. 覆盖其他窗口(除非其中一个窗口的Topmost属性设置为true)。
        /// 2. 在不影响另一方的情况下最小化、最大化和恢复。
        /// 
        /// 有些窗口需要与打开它们的窗口之间的关系。例如，集成开发环境(IDE)应用程序可能会打开属性窗口和工具窗口，这些窗口
        /// 的典型行为是覆盖创建它们的窗口。此外，这些窗口应该始终与创建它们的窗口一致关闭、最小化、最大化和恢复。这种关系
        /// 可以通过使一个窗口拥有另一个窗口来建立，并通过使用对所有者窗口的引用来设置所拥有窗口的`Owner`属性来实现。下面的
        /// 示例显示了这一点。
        /// 
        /// 所有权确定后：
        /// 1. 拥有的窗口（子窗口）可以通过检查其owner属性的值来引用其所有者窗口。
        /// 2. 所有者窗口（父窗口）可以通过检查其OwnedWindows属性的值来发现它所拥有的所有窗口。
        /// 
        /// https://docs.microsoft.com/zh-cn/dotnet/desktop/wpf/windows/?view=netdesktop-6.0#window-ownership
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Create a window and make the current window its owner
            var ownedWindow = new Window2Child();
            ownedWindow.Owner = this;
            ownedWindow.Show();
        }


        /// <summary>
        /// 消息框是一个对话框，可用于显示文本信息，并允许用户通过按钮做出决策。
        /// 下图显示了一个询问问题的消息框，并为用户提供了三个按钮来回答问题。
        /// 
        /// 要创建消息框，需要使用MessageBox类。MessageBox允许您配置消息框文本、标题、图标和按钮。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonShowMessageBoxes_Click(object sender, RoutedEventArgs e)
        {
            var arrOptions = Enum.GetValues<MessageBoxOptions>();
            var random = new Random();
            var option = arrOptions[random.Next(arrOptions.Length)];

            MessageBox.Show(
                $"Do you want to save changes? {option}",
                "Word Processor",
                MessageBoxButton.YesNoCancel,
                MessageBoxImage.Warning,
                MessageBoxResult.Cancel,
                option /* MessageBoxOptions.None */);
        }

        /// <summary>
        /// 公共对话框 - Common dialog boxes
        /// 
        /// Windows实现了不同种类的可重用对话框，这些对话框对所有应用程序都是通用的，包括用于 选择文件 和 打印 的对话框。
        /// 
        /// 由于这些对话框是由操作系统提供的，所以它们是在操作系统上运行的所有应用程序之间共享的。这些对话框提供一致的
        /// 用户体验，被称为公共对话框。当用户在一个应用程序中使用一个通用对话框时，他们不需要学习如何在其他应用程序中
        /// 使用该对话框。
        /// 
        /// WPF封装了打开文件、保存文件和打印公共对话框，并将它们作为托管类公开，供您在独立应用程序中使用。
        /// 要了解有关常见对话框的更多信息，请参阅以下文章:
        /// 1. 如何显示普通对话框
        /// 2. 显示“打开文件”对话框
        /// 3. 显示“保存文件”对话框
        /// 4. 显示打印对话框
        /// 
        /// https://docs.microsoft.com/zh-cn/dotnet/desktop/wpf/windows/how-to-open-common-system-dialog-box?view=netdesktop-6.0
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonShowCommonDialogBoxes_Click(object sender, RoutedEventArgs e)
        {

        }



        /// <summary>
        /// 自定义对话框
        /// 虽然普通对话框很有用，并且应该在可能的情况下使用，但它们不支持特定于域的对话框的需求。
        /// 在这些情况下，您需要创建自己的对话框。正如我们将看到的，对话框是一个具有特殊行为的窗口。
        /// 窗口实现了这些行为，您可以使用该窗口创建自定义模态和非模态对话框。
        /// 
        /// 在创建自己的对话框时，需要考虑许多设计方面的考虑。虽然应用程序窗口和对话框都有相似之处，
        /// 比如共享同一个基类，但对话框是用于特定目的的。当您需要提示用户提供某种信息或响应时，通常需要一个对话框。
        /// 通常，当对话框(模态)显示时，应用程序将暂停，从而限制对应用程序其余部分的访问。关闭对话框后，
        /// 应用程序继续运行。但是，将交互单独限制在对话框中并不是必需的。
        /// 
        /// 当WPF窗口关闭时，它不能重新打开。自定义对话框是WPF窗口，应用相同的规则。要了解如何关闭窗口，请参见如何关闭窗口或对话框。
        /// 
        /// 实现一个对话框
        /// 
        /// 设计对话框时，遵循以下建议来创建良好的用户体验:
        /// ❌不要干扰对话框窗口。对话框的体验是让用户输入一些数据，或者做出选择。
        /// ✔️提供一个OK按钮来关闭窗口。
        /// ✔️将OK按钮的IsDefault属性设置为true，以允许用户按ENTER键接受并关闭窗口。
        /// ✔️考虑添加一个Cancel按钮，以便用户可以关闭窗口并表示他们不想继续。
        /// ✔️将Cancel按钮的IsCancel属性设置为true，以允许用户按ESC键关闭窗口。
        /// ✔️设置窗口的标题，以准确描述对话框表示的内容，或者用户应该对对话框做什么。
        /// ✔️设置窗口的最小宽度和高度值，防止用户将窗口调整得太小。
        /// ✔️考虑禁用调整窗口大小的能力，如果ShowInTaskbar设置为false。你可以通过将ResizeMode设置为NoResize来禁用调整大小
        /// 
        /// 打开一个UI元素对话框
        /// 
        /// 对话框的用户体验还扩展到菜单栏或打开它的窗口的按钮。当菜单项或按钮运行的函数需要用户通过对话框进行交互才能
        /// 继续该函数时，控件应该在其标题文本的末尾使用省略号:
        /// 
        /// 当一个菜单项或按钮运行一个函数，该函数显示一个不需要用户交互的对话框，例如About对话框，省略号是不需要的。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void formatMarginsButton_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new Window2Margins();

            // Display the dialog box and read the response
            bool? result = dialog.ShowDialog();

            // 打开另一个窗口，特别是一个模态对话框，是向调用代码返回状态和信息的好方法。
            // 当通过调用ShowDialog()显示对话框时，打开对话框的代码将等待，直到ShowDialog方法返回。
            // 当方法返回时，调用它的代码需要决定是继续处理还是停止处理。
            // 用户通常通过单击对话框上的 OK 或 Cancel 按钮来表示这一点。

            // 当OK按钮被按下时，ShowDialog应该被设计为返回true，而Cancel按钮应该返回false。
            // 这是通过在按下按钮时设置DialogResult属性来实现的。

            // 只有使用ShowDialog()显示对话框时，才能设置DialogResult属性。设置了DialogResult属性后，对话框关闭。
            // 如果一个按钮的 IsCancel 属性设置为true，并且使用 ShowDialog() 打开窗口，ESC键将关闭窗口并将DialogResult设置为false。
            // 有关关闭对话框的详细信息，请参见如何关闭窗口或对话框。

            // 处理响应
            // ShowDialog()返回一个布尔值，表示用户是接受还是取消对话框。
            // 如果您在提醒用户一些事情，但不要求他们做出决定或提供数据，您可以忽略响应。
            // 还可以通过检查DialogResult属性来检查响应。下面的代码展示了如何处理响应:
            if (result == true)
            {
                // User accepted the dialog box
                MessageBox.Show("Your request will be processed.");
            }
            else
            {
                // User cancelled the dialog box
                MessageBox.Show("Sorry it didn't work out, we'll try again later.");
            }
        }

        /// <summary>
        /// 非模态对话框
        /// 
        /// 要显示非模态对话框，调用 show() 。对话框至少应该提供一个关闭按钮。
        /// 可以提供其他按钮和交互元素来运行特定的功能，例如Find Next按钮来在单词搜索中查找下一个单词。
        /// 
        /// 因为非模态对话框不会阻止调用代码继续，所以必须提供返回结果的不同方式。你可以做以下其中之一:
        /// 1. 在窗口上公开数据对象属性。
        /// 2. 处理代码中的 ` Window.Closed` 事件。
        /// 3. 在窗口上创建当用户选择对象或按下特定按钮时引发的事件。
        /// 
        /// 下面的示例使用 `Window.Closed` 事件，在对话框关闭时向用户显示消息框。
        /// 显示的消息引用已关闭对话框的属性。有关关闭对话框的详细信息，请参见如何关闭窗口或对话框。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
        {
            var marginsWindow = new Window2Margins();

            marginsWindow.Closed += (sender, eventArgs) =>
            {
                MessageBox.Show($"You closed the margins window! It had the title of {marginsWindow.Title}");
            };

            marginsWindow.Show();
        }
    }
}
